package com.example.netty_pipline.pipeline;

/**
 * 抽象的ChannelHandlerContext实现
 * 提供处理器上下文的基本功能和事件传播机制
 */
public abstract class AbstractChannelHandlerContext implements ChannelHandlerContext {
    
    protected final ChannelPipeline pipeline;
    protected final String name;
    protected final ChannelHandler handler;
    
    volatile AbstractChannelHandlerContext next;
    volatile AbstractChannelHandlerContext prev;
    
    protected AbstractChannelHandlerContext(ChannelPipeline pipeline, String name, ChannelHandler handler) {
        this.pipeline = pipeline;
        this.name = name;
        this.handler = handler;
    }
    
    @Override
    public ChannelPipeline pipeline() {
        return pipeline;
    }
    
    @Override
    public String name() {
        return name;
    }
    
    @Override
    public ChannelHandler handler() {
        return handler;
    }
    
    // 入站事件传播方法
    @Override
    public ChannelHandlerContext fireChannelActive() {
        invokeChannelActive(findContextInbound());
        return this;
    }
    
    @Override
    public ChannelHandlerContext fireChannelInactive() {
        invokeChannelInactive(findContextInbound());
        return this;
    }
    
    @Override
    public ChannelHandlerContext fireChannelRead(Object msg) {
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }
    
    @Override
    public ChannelHandlerContext fireChannelReadComplete() {
        invokeChannelReadComplete(findContextInbound());
        return this;
    }
    
    @Override
    public ChannelHandlerContext fireUserEventTriggered(Object evt) {
        invokeUserEventTriggered(findContextInbound(), evt);
        return this;
    }
    
    @Override
    public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
        invokeExceptionCaught(findContextInbound(), cause);
        return this;
    }
    
    // 出站操作传播方法
    @Override
    public ChannelHandlerContext bind(Object localAddress) {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeBind(localAddress);
        return this;
    }
    
    @Override
    public ChannelHandlerContext connect(Object remoteAddress, Object localAddress) {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeConnect(remoteAddress, localAddress);
        return this;
    }
    
    @Override
    public ChannelHandlerContext disconnect() {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeDisconnect();
        return this;
    }
    
    @Override
    public ChannelHandlerContext close() {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeClose();
        return this;
    }
    
    @Override
    public ChannelHandlerContext write(Object msg) {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeWrite(msg);
        return this;
    }
    
    @Override
    public ChannelHandlerContext flush() {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeFlush();
        return this;
    }
    
    @Override
    public ChannelHandlerContext read() {
        AbstractChannelHandlerContext next = findContextOutbound();
        next.invokeRead();
        return this;
    }
    
    // 查找下一个入站处理器上下文
    private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this.next;
        while (ctx != null) {
            if (ctx.handler() instanceof ChannelInboundHandler) {
                return ctx;
            }
            ctx = ctx.next;
        }
        return null;
    }
    
    // 查找下一个出站处理器上下文
    private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this.prev;
        while (ctx != null) {
            if (ctx.handler() instanceof ChannelOutboundHandler) {
                return ctx;
            }
            ctx = ctx.prev;
        }
        return null;
    }
    
    // 入站事件调用方法
    private void invokeChannelActive(AbstractChannelHandlerContext next) {
        if (next != null) {
            try {
                ((ChannelInboundHandler) next.handler()).channelActive(next);
            } catch (Exception e) {
                next.invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeChannelInactive(AbstractChannelHandlerContext next) {
        if (next != null) {
            try {
                ((ChannelInboundHandler) next.handler()).channelInactive(next);
            } catch (Exception e) {
                next.invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeChannelRead(AbstractChannelHandlerContext next, Object msg) {
        if (next != null) {
            try {
                ((ChannelInboundHandler) next.handler()).channelRead(next, msg);
            } catch (Exception e) {
                next.invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeChannelReadComplete(AbstractChannelHandlerContext next) {
        if (next != null) {
            try {
                ((ChannelInboundHandler) next.handler()).channelReadComplete(next);
            } catch (Exception e) {
                next.invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeUserEventTriggered(AbstractChannelHandlerContext next, Object evt) {
        if (next != null) {
            try {
                ((ChannelInboundHandler) next.handler()).userEventTriggered(next, evt);
            } catch (Exception e) {
                next.invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeExceptionCaught(AbstractChannelHandlerContext next, Throwable cause) {
        if (next != null) {
            try {
                next.handler().exceptionCaught(next, cause);
            } catch (Exception e) {
                // 如果异常处理也抛出异常，记录日志但不继续传播
                System.err.println("Exception while handling exception: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    
    // 出站操作调用方法
    private void invokeBind(Object localAddress) {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).bind(this, localAddress);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeConnect(Object remoteAddress, Object localAddress) {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).connect(this, remoteAddress, localAddress);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeDisconnect() {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).disconnect(this);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeClose() {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).close(this);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeWrite(Object msg) {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).write(this, msg);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeFlush() {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).flush(this);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    private void invokeRead() {
        if (handler instanceof ChannelOutboundHandler) {
            try {
                ((ChannelOutboundHandler) handler).read(this);
            } catch (Exception e) {
                invokeExceptionCaught(e);
            }
        }
    }
    
    // 内部异常处理方法
    private void invokeExceptionCaught(Throwable cause) {
        try {
            handler.exceptionCaught(this, cause);
        } catch (Exception e) {
            System.err.println("Exception while handling exception: " + e.getMessage());
            e.printStackTrace();
        }
    }
}